pub trait Formatter {
    fn format(&self, input: &mut String) -> bool;
}

struct MarkdownFormatter;
impl Formatter for MarkdownFormatter {
    fn format(&self, input: &mut String) -> bool {
        input.push_str("\nformatted with Markdown formatter");
        true
    }
}

struct RustFormatter;
impl Formatter for RustFormatter {
    fn format(&self, input: &mut String) -> bool {
        input.push_str("\nformatted with Rust formatter");
        true
    }
}

struct HtmlFormatter;
impl Formatter for HtmlFormatter {
    fn format(&self, input: &mut String) -> bool {
        input.push_str("\nformatted with HTML formatter");
        true
    }
}

pub fn format(input: &mut String, formatters: Vec<&dyn Formatter>) {
    for formatter in formatters {
        formatter.format(input);
    }
}
#[test]
fn test1() {
    let mut text = "Hello world!".to_string();
    let html: &dyn Formatter = &HtmlFormatter;
    let rust = &RustFormatter;
    let formatters = vec![html, rust];
    format(&mut text, formatters);

    println!("text: {}", text);
}
#[test]
fn test_easy(){
    let x=4;
    let y=x;
    let z=y.clone();
    ///on stack copy and clone no difference。
    println!("{:p}",&x); //0x70000421383c  12
    println!("{:p}",&y); //0x700004213840  16
    println!("{:p}",&z); //0x700004213844  4
}

fn gives_ownership()->String{
    let s=String::from("hello from inner func");
    s //s moves out to the calling function
}

fn takes_and_gives_back(str: String)->String{
    str //
}
#[test]
fn test_ownership_moves(){
    let s1=gives_ownership();
    let s2=String::from("hello");
    let s3=takes_and_gives_back(s2);
    println!("{}",s1);
    println!("{}",s3);
}
#[test]
fn test_mutable_borrow(){
    let mut s =String::from("hello");
    let s1=&s; //引用类型变量
    let s2=&s; //引用类型变量,也会move所有权
    println!("{:?},{:?}",s1,s2);
    //s1,s2 moved here.
    let r3 = &mut s; // no problem
    println!("{}", r3);
}

fn first_character(str:&str)->&str{
    for (i, &item) in str.as_bytes().iter().enumerate() {
        if item == b' ' {
            return &str[0..i];
        }
    }
    return &str[..]
}
#[test]
fn test_first_character(){
    let s=String::from("hello world");
    let s1=first_character(&s);
    let s12=first_character(&s[0..6]);
    println!("slice,first word:{}",s1);
    println!("slice,first word:{}",s12);
    println!("slice,first word:{}",s1);
    let a=[1,2,3,4,5];
    let slice=&a[1..3]; //slice 类型&[]
}
struct User<'a>{
    active:bool,
    name: &'a str,  //原因，怕&的对象已经drop。
    email: &'a str, //if not exits 'a ，则编译报错。
    sign_in_account: u64,
}

fn area(width: u32, height: u32) -> u32 {
    width * height
}
#[test]
fn test_area(){
    let d1=(3,5);
    let area=area(3,5);
    let area2=area2(d1);
    println!("area:{}",area);
    println!("area:{}",area2);

}

fn area2(dimensions: (u32, u32)) -> u32 {
    dimensions.0 * dimensions.1
}

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
#[test]
fn test_rectangle() {
    let scale = 2;
    let rect1 = Rectangle {
        width: dbg!(30 * scale),  //赋值60 并print 30 * scale = 60
        //dbg! marco接收传参的所有权，并返回一个值以及它的所有权。
        height: 50,
    };
    dbg!(&rect1);
    let a=Some("abc");
    let mut n:Option<i32>=None;
    n=Some(123);
    println!("{:#?}",n);
}
fn plus_one(one:Option<i32>)->Option<i32>{
    match one{
        Some(i) => Some(i+1),
        None => None,
    }
}
#[test]
fn test_plus_one(){
    let o=plus_one(Some(5));
    println!("{:?}",o);
}
#[test]
fn test_collection(){
    let mut v=vec![1,23,34,5];
    for x in  &mut v { //v首先是mut 然后使用时必须用&mut v
        *x += 10;  //必须解引用才能加
    }
    for j in &v {
        println!("{:?}",j);
    }
    let s="hello";
    let mut s1=String::from("abc");
    s1.push_str(s);
    println!("{}",s);
    println!("{}",s1);
    let he=String::from("hello");
    let world=String::from("world!");
    let total=he+&world;
    println!("{}",total);
    // println!("{}",he)
    let hello = "Здравствуйте";
    let s2 = &hello[0..4];
    println!("{:?}",s2);
    use std::collections::HashMap;
    let mut scores=HashMap::new();
    scores.insert(String::from("first"),200);
    scores.insert(String::from("second"),100);

}